#ifndef LOG_H_
#define LOG_H_ 1
#define S_FILE S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH
#include <iostream>
#include <memory>
#include <thread>
#include <assert.h>

#include <stdarg.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/types.h>

#include "blockqueue.h"
#include "../buffer/buff.h"
//对日志文件的操作使用 原生C 中的 文件操作函数，不采用linux中的系统调用
//异步写入：将要写入的信息push进阻塞队列，使用c++11中的 std::thread 为原型对阻塞队列中的信息进行操作。
//          异步写入另外加锁
//同步写入：直接写入
//时间信息：使用linux原生的 timeval、tm 结构体，原生 C 的格式化 printf
//根据不同的等级写入不同等级的日志信息
//单例模式:
//      懒汉模式：函数内部局静态对象
//      饿汉模式：全局静态对象
class Log
{
public:
    void init(int level,const char* path = "./Logs",const char* suffix=".log",bool isasync = 1);
    static Log* getInstance();
    static void wakeWriteThread();  

    void write(int level,const char *format,...);
    void wake();

    int getlevel();
    void setlevel(int level);
    bool isopen(){return isOpen_;}
private:    
    Log();
    ~Log();
    void addLevelTile(int level);
    void AsyncWriteLog();

private:
    static const int LOG_PATH_LEN = 256;
    static const int LOG_NAME_LEN = 256;
    static const int MAX_LINE   = 500;


    const char * path_;
    const char * suffix_;

    int countLine_;
    int level_;
    int maxLine_;
    int toDay_;

    bool isOpen_;
    bool isAsync_;

    FILE* fp;
    int fd_;
    std::mutex mutex_;
    std::unique_ptr<BlockQueue<std::string>> deque_;
    std::unique_ptr<std::thread> WriteThread_;

    Buffer_::Buffer buff_;
};

#define LOG_BASE(level,format,...) do{ \
    Log* log = Log::getInstance(); \
    if((log->isopen()) && (log->getlevel() <= level) ){ \
    log->write(level,format,##__VA_ARGS__); \
    log->wake(); \
        } \
    }while(0); 
#define LOG_DEBUG(format,...) do{LOG_BASE(0,format,##__VA_ARGS__)}while(0);
#define LOG_INFO(format,...) do{LOG_BASE(1,format,##__VA_ARGS__)}while(0);
#define LOG_WARN(format,...) do{LOG_BASE(2,format,##__VA_ARGS__)}while(0);
#define LOG_ERRNO(format,...) do{LOG_BASE(3,format,##__VA_ARGS__)}while(0);
#endif